package de.iritgo.skillfull.component.motion;

import java.awt.Point;
import java.awt.Rectangle;

import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;

import de.iritgo.skillfull.collision.QuadTree;
import de.iritgo.skillfull.component.Component;
import de.iritgo.skillfull.component.MotionComponentImpl;
import de.iritgo.skillfull.component.visitor.PositionVisitor;
import de.iritgo.skillfull.component.visitor.Visitor;
import de.iritgo.skillfull.config.ConfigManager;
import de.iritgo.skillfull.entity.Entity;

public class MoveFieldComponentImpl extends MotionComponentImpl implements MoveFieldComponent
{
	/* The config manager */
	private ConfigManager configManager;
	
	private Point destination;
	
	private float rotation;
	
	private float duration;
	
	private float speed;
	
	private float nextTick = -1;
	
	private int dstX;

	private int dstY;

	private boolean destinationReached;
	
	private Rectangle validArea;

	/* Set the config manager */
	public void setConfigManager(ConfigManager configManager) 
	{
		this.configManager = configManager;
	}

	public void init ()
	{
		nextTick = -1;
		x = -32;
		y = -32;
		destinationReached = false;
		destination = null;
		dstX = -33;
		dstY = -33;
		validArea = null;
		active = false;
	}

	public Point getDestination() 
	{
		return destination;
	}

	public void setDestination (Point destination) 
	{
		this.destination = destination;
	}

	public float getRotation() 
	{
		return rotation;
	}

	public void setRotation(float rotation) 
	{
		this.rotation = rotation;
	}
	
	public float getSpeed () 
	{
		return speed;
	}

	public void setSpeed (float speed) 
	{
		this.speed = speed;
	}

	public float getDuration() 
	{
		return duration;
	}

	public void setDuration(float duration) 
	{
		this.duration = duration;
	}

	@Override
	public void accept (Visitor visitor)
	{
		visitor.visit (this);
		
		if (components == null)
			return;

		for (Component component : components)
		{
			component.accept (visitor);
		}
	}

	public void moveTo (Point destination) 
	{
		this.destination = destination;
		this.destinationReached = false;

		dstX = (int) destination.x;
		dstY = (int) destination.y;
		
		rotation = (float) java.lang.Math.toDegrees (Math.atan2 (x - dstX, y - dstY) * -1);
	}

	public void moveTo (float direction, Rectangle validArea) 
	{
		this.destinationReached = false;
		rotation = direction;
		this.validArea = validArea;
	}

	public void stop() 
	{
		dstX = (int) x;
		dstY = (int) y;
		destinationReached = true;
	}

	public void render(GameContainer container, Graphics g, Entity entity) 
	{
		if (configManager.functionActive("showEntityPos"))
		{
			g.drawString ("X:" + x + "Y:" + y + "DX:" + dstX + "DY:" + dstY, x, y + 32);
		}
	}
	
	/**
	 * Move the component to the right position...
	 */
	public void update (GameContainer container, int delta, Entity entity)
	{
		nextTick -= delta;
		
		while (nextTick < 0)
		{
			nextTick += duration / speed;
			
			if (! active)
				continue;

			if (! active && ! destinationReached)
				continue;
			
			if (validArea == null && dstX != ((int) x))
			{
				x+= 1 * java.lang.Math.sin (java.lang.Math.toRadians(rotation));
			}
			else if (validArea != null)
			{
				x+= 1 * java.lang.Math.sin (java.lang.Math.toRadians(rotation));
			}
			if (validArea == null && dstY != ((int) y))
			{
				y-= 1 * java.lang.Math.cos (java.lang.Math.toRadians(rotation));
			}
			else if (validArea != null)
			{
				y-= 1 * java.lang.Math.cos (java.lang.Math.toRadians(rotation));
			}

			if (x < -64)
			{
				destinationReached = true;
				x = -64;
			}
			if (x + 32 > 1280 * QuadTree.MULTI)
			{
				x = 1280 + 32;
				destinationReached = true;
			}
			
			if (y < -64)
			{
				destinationReached = true;
				y = -64;
			}
			if (y + 32 > 1024 * QuadTree.MULTI)
			{
				destinationReached = true;
				y = 1024 + 32;
			}
		}

		if (components == null)
			return;

		for (Component component : components)
		{
			component.update (container, delta, entity);
		}
	}

	/**
	 * Has the component the dst reached
	 * @return true if reached
	 */
	public boolean dstReached () 
	{
		if ((((int) x) == dstX && ((int) y) == dstY) || destinationReached || (validArea != null && ! validArea.contains(x,y)))
		{
			active = false;
			destinationReached = true;
			return true;
		}
		return false;
	}


	public void printConfiguration ()
	{
		if (components == null)
			return;

		for (Component component : components)
		{
			component.printConfiguration ();
		}
	}

	public void removed(Entity entity) 
	{
		active = false;
		validArea = null;
	}
}
